﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Threading;
using System.Text.RegularExpressions;
using NovoSerDes;
using NovoDataBase;
using static NovoUI.UserCtrl.FormScript;
using System.Globalization;
using System.Xml.Linq;
using System.CodeDom;

namespace NovoUI.UserCtrl
{

    #region 
    //    Create a new command SOP:
    //1. Create a string array to save the command list
    //2. Add command list to CMDPool in "InitCMDPool()" function
    //3. Add the command to eCMDList
    //4. Check "ParameterCheck" function and add new rules
    //5. Add new command operation case in "btn_Script_Excute_Click" event
    #endregion
    public partial class FormScript : UserControl
    {
        SerDesComm commDev;
        IRegOperation myRegOp;
        List<ScriptCMD> validCMDList = new List<ScriptCMD>();
        OutputLogCtrl logWin = new OutputLogCtrl();

        byte currentChipAddr = 0x42 << 1;
        IICMode currentI2CMode = IICMode.A16D32;
        IICMode iicModeForCompile = IICMode.A16D32;

        Color color_default = Color.Black;
        Color color_CMD = Color.DarkBlue;
        Color color_Parma = Color.DarkGreen;
        Color color_comment = Color.DarkGray;

        eExcuteStatus excuteStatus = eExcuteStatus.Stopped;
        eExcuteStatus ChangeStatus
        {
            set 
            {
                this.excuteStatus = value;
                switch (this.excuteStatus)
                {
                    case eExcuteStatus.Paused:
                        this.btn_Script_Excute.Text = "Paused";
                        break;
                    case eExcuteStatus.Running:
                        this.btn_Script_Excute.Text = "Excuting";
                        break;

                    default:
                        this.btn_Script_Excute.Text = "Excute";
                        break;
                }
            }
        }

        #region Command Definition
        List<string> AllCommands = new List<string>();
        List<string[]> CMDPool = new List<string[]>();  //Include all command key word
        string[] SetIICMode = new string[] { "SetIICMode".ToUpper(), "IICMode".ToUpper()};
        string[] SetChipAddr = new string[] { "SetChipAddr".ToUpper(), "ChipAddr".ToUpper() };
        string[] SetDelay = new string[] {"SetDelay".ToUpper(), "Delay".ToUpper() };
        string[] Paused = new string[] { "Pause".ToUpper(),"Paused".ToUpper() };
        string[] IICSingleWrite = new string[] {"IICSingleWrite".ToUpper(), "IICWrite".ToUpper(), "IICWr".ToUpper(), "IICSWr".ToUpper() };
        string[] IICSingleRead = new string[] { "IICSingleRead".ToUpper(), "IICRead".ToUpper(), "IICRd".ToUpper(), "IICSRd".ToUpper() };
        string[] IICBurstWrite = new string[] {"IICBurstWrite".ToUpper(), "IICBWr".ToUpper() };
        string[] IICBurstRead = new string[] {"IICBrustRead".ToUpper(), "IICBRd".ToUpper() };
        string[] IICSetBit = new string[] { "IICSetBit".ToUpper(), "IICSB".ToUpper()};
        string[] IICSetBitField = new string[] { "IICSetBitField".ToUpper(), "IICSBF".ToUpper() };
        string[] IICReadBitField = new string[] {"IICReadBitField".ToUpper(), "IICRdBF".ToUpper() };
        string[] IICClearBit = new string[] { "IICClearBit".ToUpper(), "IICCB".ToUpper() };
        string[] IICWaitUntil = new string[] { "IICWaitUntil".ToUpper(), "IICWU".ToUpper()};
        string[] IICWaitBFUntil = new string[] { "IICWaitBitFieldUntil".ToUpper(), "IICWaitBFUntil".ToUpper(), "IICWBFU".ToUpper() };
        #region Test bus commands
        string[] TestBusWrite = new string[] {"TestBusWrite".ToUpper(), "TBWrite".ToUpper(), "TBWr".ToUpper()};
        string[] TestBusRead = new string[] { "TestBusRead".ToUpper(), "TBRead".ToUpper(), "TBRd".ToUpper() };
        string[] TestBusSetBitField = new string[] {"TestBusSetBitField".ToUpper(), "TBSBF".ToUpper() };
        string[] TestBusReadBitField = new string[] {"TestBusReadBitField".ToUpper(), "TBRdBF".ToUpper() };
        #endregion Test bus commands
        #endregion

        public FormScript(SerDesComm _commDev)
        {
            InitializeComponent();
            commDev = _commDev;
            this.panel_log.Controls.Add(logWin);
            logWin.Dock = DockStyle.Fill;
            this.richtxt_ScriptView.SelectionIndent = 8;

            InitCMDPool();
            InitRowLineUI();

            this.cmb_IICMode.SelectedItem = IICMode.A16D32.ToString();
            //Console.WriteLine(IICMode.A16D32.ToString());
        }

        #region Funcs
        private void InitCMDPool()
        {
            CMDPool.Clear();
            AllCommands.Clear();
            // Add sequence should same with eCMDList
            CMDPool.Add(SetIICMode);        
            AllCommands.AddRange(SetIICMode.ToList<string>());
            CMDPool.Add(SetChipAddr);       
            AllCommands.AddRange(SetChipAddr.ToList<string>());
            CMDPool.Add(SetDelay);
            AllCommands.AddRange(SetDelay.ToList<string>());
            CMDPool.Add(Paused);
            AllCommands.AddRange(Paused.ToList<string>());
            CMDPool.Add(IICSingleWrite);
            AllCommands.AddRange(IICSingleWrite.ToList<string>());
            CMDPool.Add(IICSingleRead);
            AllCommands.AddRange(IICSingleRead.ToList<string>());
            CMDPool.Add(IICBurstWrite);
            AllCommands.AddRange(IICBurstWrite.ToList<string>());
            CMDPool.Add(IICBurstRead);
            AllCommands.AddRange(IICBurstRead.ToList<string>());
            CMDPool.Add(IICSetBit);
            AllCommands.AddRange(IICSetBit.ToList<string>());
            CMDPool.Add(IICSetBitField);
            AllCommands.AddRange(IICSetBitField.ToList<string>());
            CMDPool.Add(IICReadBitField);
            AllCommands.AddRange(IICReadBitField.ToList<string>());
            CMDPool.Add(IICClearBit);
            AllCommands.AddRange(IICClearBit.ToList<string>());
            CMDPool.Add(IICWaitUntil);
            AllCommands.AddRange(IICWaitUntil.ToList<string>());
            CMDPool.Add(IICWaitBFUntil);
            AllCommands.AddRange(IICWaitBFUntil.ToList<string>());

            //TestBus, SerDes Debug only
            CMDPool.Add(TestBusWrite);
            AllCommands.AddRange(TestBusWrite.ToList<string>());
            CMDPool.Add(TestBusRead);
            AllCommands.AddRange(TestBusRead.ToList<string>());
            CMDPool.Add(TestBusSetBitField);
            AllCommands.AddRange(TestBusSetBitField.ToList<string>());
            CMDPool.Add(TestBusReadBitField);
            AllCommands.AddRange(TestBusReadBitField.ToList<string>()); 
        }

        private void InitRowLineUI()
        {
            this.rtb_rowIndex.Width = panel2.Width;
            this.rtb_rowIndex.Location = new Point(0, 0);
            this.rtb_rowIndex.Height = panel2.Height;
        }

        private void UpdateLableRowIndex()
        {
            this.rtb_rowIndex.Font = this.richtxt_ScriptView.Font;

            int p = richtxt_ScriptView.GetPositionFromCharIndex(0).Y % (richtxt_ScriptView.Font.Height + 2);
            p = p - 1;

            //Console.WriteLine("1st char location:{0}", richtxt_ScriptView.GetPositionFromCharIndex(0).Y);
            //Console.WriteLine("Font Height:{0}, p:{1}", richtxt_ScriptView.Font.Height, p);
            //Console.WriteLine("Edit height:{0}", this.richtxt_ScriptView.Height);

            this.rtb_rowIndex.Location = new Point(0, p);
            this.rtb_rowIndex.Height = this.panel2.Height - p;


            Point pos = new Point(0, 0);
            int firstIx = this.richtxt_ScriptView.GetCharIndexFromPosition(pos);
            int firstLine = this.richtxt_ScriptView.GetLineFromCharIndex(firstIx);

            //now we get index of last visible char and number of last visible line
            pos.X += this.richtxt_ScriptView.ClientRectangle.Width;
            pos.Y += this.richtxt_ScriptView.ClientRectangle.Height;
            int lastIndex = this.richtxt_ScriptView.GetCharIndexFromPosition(pos);
            int lastLine = this.richtxt_ScriptView.GetLineFromCharIndex(lastIndex);

            //this is point position of last visible char,
            //we'll use its Y value for calculating numberLabel size
            pos = this.richtxt_ScriptView.GetPositionFromCharIndex(lastIndex);

            rtb_rowIndex.Text = "";
            for (int i = firstLine; i <= lastLine + 1; i++)
            {
                rtb_rowIndex.Text += i + 1 + "\r\n";
            }
        }

        public static string GetLastWord(string str, int i)
        {
            string x = str;
            //Regex reg = new Regex("[a-zA-Z0-9]", RegexOptions.RightToLeft);
            Regex reg = new Regex(@"\w+", RegexOptions.RightToLeft);
            x = reg.Match(x).Value;

            Regex reg2 = new Regex(@"\s");
            x = reg2.Replace(x, "");
            return x;
        }

        private void RefreshWholeTextFormat(RichTextBox _rtb)
        {
            RichTextBox rtb = _rtb;
            int currentIx = rtb.SelectionStart;     

            for (int ix = 0; ix < rtb.Lines.Length; ix++)
            {
                SetFormat_Line(rtb, ix);
                //if (rtb.Lines[ix].Length == 0)
                //    continue;
                //
                //tempSelStart = rtb.GetFirstCharIndexFromLine(ix);
                //tempSelLen = rtb.Lines[ix].Length;                
                //
                //if (rtb.Lines[ix].StartsWith(@"//"))
                //{                    
                //    SetSelectedText(rtb, tempSelStart, tempSelLen, color_comment);
                //    //Point pos = rtb.GetPositionFromCharIndex(0);
                //}
                //else
                //{
                //    tempStr = rtb.Lines[ix].Split(new char[] { ' ', ',', '|' }, StringSplitOptions.RemoveEmptyEntries);
                //    if (tempStr.Length > 0 && AllCommands.Contains(tempStr[0].ToUpper()))
                //        SetSelectedText(rtb, tempSelStart, tempStr[0].Length, color_CMD);
                //}
            }

            rtb.SelectionStart = currentIx;
        }

        private bool IfValidKeyPress(int _keyValue)
        {
            bool ret = false;

            /* 包含特殊字符有：',', ';', '|', '[', ']', '/' */
            int[] validKeyList = new int[] {(int)Keys.Space, (int)Keys.Back, (int)Keys.Delete, (int)Keys.Enter,
            (int)Keys.Oem1, (int)Keys.Oem2, (int)Keys.Oem5, (int)Keys.Oem6, (int)Keys.Oemcomma, (int)Keys.OemOpenBrackets};

            if ((_keyValue >= 0x30) && (_keyValue <= 0x5A)) // D0-D9 + A-Z
                ret = true;
            else if ((_keyValue >= 0x60) && (_keyValue <= 0x69)) // Num0-9
                ret = true;
            else if (validKeyList.Contains(_keyValue))
                ret = true;


            //Console.WriteLine("KeyValue {0}, return {1}", _keyValue.ToString("X2"), ret);

            return ret;
        }

        private void SetSelectedText(RichTextBox rtb, int startIx, string text, Color setColor)
        {
            if (startIx < text.Length)
                return;

            rtb.Select(startIx - text.Length, text.Length);
            rtb.SelectionColor = setColor;

            rtb.Select(startIx + text.Length, 0);
            rtb.SelectionColor = Color.Black;
        }

        private void SetFormat_Line(RichTextBox rtb)
        {
            int startIx = rtb.SelectionStart;
            int currentLine = rtb.GetLineFromCharIndex(startIx);

            try
            {
                if (rtb.Lines.Length > 0 && rtb.Lines[currentLine].Length > 0)
                {
                    string txtLine = rtb.Lines[currentLine];
                    int tempIx = 0;
                    string[] tempStr = txtLine.Split(new char[] { ' ', ',', '|' }, StringSplitOptions.RemoveEmptyEntries);
                    if (txtLine.StartsWith(@"//") || txtLine.StartsWith(@"/*"))
                        SetSelectedText(rtb, rtb.GetFirstCharIndexFromLine(currentLine), rtb.Lines[currentLine].Length, color_comment);
                    else                    
                    {
                        SetSelectedText(rtb, rtb.GetFirstCharIndexFromLine(currentLine), txtLine.Length, color_default);
                        if (tempStr.Length > 0 && AllCommands.Contains(tempStr[0].ToUpper()))
                        {
                            tempIx = txtLine.IndexOf(tempStr[0]);
                            SetSelectedText(rtb, rtb.GetFirstCharIndexFromLine(currentLine) + tempIx, tempStr[0].Length, color_CMD);
                        }

                        if (txtLine.Contains(@"//") || txtLine.Contains(@"/*"))
                        {
                            tempIx = txtLine.IndexOf("/");
                            SetSelectedText(rtb, rtb.GetFirstCharIndexFromLine(currentLine) + tempIx, txtLine.Length - tempIx, color_comment);
                        }
                    }
                }
            }
            catch { }
            finally { rtb.SelectionStart = startIx; }            
        }

        private void SetFormat_Line(RichTextBox rtb, int setLine)
        {
            int startIx = rtb.GetFirstCharIndexFromLine(setLine);            

            try
            {
                if (rtb.Lines.Length > 0 && rtb.Lines[setLine].Length > 0)
                {
                    string txtLine = rtb.Lines[setLine];
                    int tempIx = 0;
                    string[] tempStr = txtLine.Split(new char[] { ' ', ',', '|' }, StringSplitOptions.RemoveEmptyEntries);
                    if (txtLine.StartsWith(@"//") || txtLine.StartsWith(@"/*"))
                        SetSelectedText(rtb, startIx, txtLine.Length, color_comment);
                    else
                    {
                        SetSelectedText(rtb, startIx, txtLine.Length, color_default);
                        if (tempStr.Length > 0 && AllCommands.Contains(tempStr[0].ToUpper()))
                        {
                            tempIx = txtLine.IndexOf(tempStr[0]);
                            SetSelectedText(rtb, startIx + tempIx, tempStr[0].Length, color_CMD);
                        }

                        if (txtLine.Contains(@"//") || txtLine.Contains(@"/*"))
                        {
                            tempIx = txtLine.IndexOf("/");
                            SetSelectedText(rtb, startIx + tempIx, txtLine.Length - tempIx, color_comment);
                        }
                    }
                }
            }
            catch { }
            finally { rtb.SelectionStart = startIx; }
        }

        private void SetSelectedText(RichTextBox rtb, int startIx, int len, Color setColor)
        {
            rtb.Select(startIx, len);
            rtb.SelectionColor = setColor;

            rtb.Select(startIx + len, 0);
            rtb.SelectionColor = Color.Black;
        }

        private void PrintErr(string msg)
        {
            logWin.AppendLog(msg, Color.Red);
        }

        private void PrintInfo(string msg)
        {
            logWin.AppendLog(msg);
        }

        private void PrintCMDLog(ScriptCMD sCMD, bool ifOK)
        {
            string tempMsg = String.Format("[CMD@L{0}] {1} ", sCMD.lineNo, sCMD.cmd.ToString());
            logWin.AppendLog(tempMsg, color_CMD, false, false);

            tempMsg = "[Param] ";
            for(int ix = 0; ix < sCMD.paramStr.Count; ix++) 
            {
                tempMsg += sCMD.paramStr[ix] + " ";            
            }
            logWin.AppendLog(tempMsg, color_Parma, false, false);

            if (ifOK)
            {
                PrintInfo(": OK");
            }
            else
            {
                PrintErr(": Failed!");
            }            
        }

        private eCMDList CommandDecode(string msg)
        {
            string tempCMDStr = msg.ToUpper();

            for (int ix = 0; ix < CMDPool.Count; ix++)
            {
                if (CMDPool[ix].Contains(tempCMDStr))
                    return (eCMDList)ix;
            }

            return eCMDList.Unknown;
        }

        private IICMode IICModeDecode(string msg)
        {
            IICMode i2cMode = IICMode.A16D32;
            if (Enum.TryParse(msg.ToUpper(), true, out i2cMode))
                return i2cMode;
            else
                return IICMode.None;
        }

        private T StringToEnum<T>(string value)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                return default(T);
            }

            //Enum.TryParse(value, true, out )
            // return default(IICMode.None) once convert wrong
            return (T)Enum.Parse(typeof(T), value);
        }

        private bool ParameterCheck(string[] msgIn, ref ScriptCMD sCmd)
        {
            bool ret = true;
            int byteCnt_RegAddr = ((byte)iicModeForCompile >> 4) & 0x0F;
            int byteCnt_RegData = ((byte)iicModeForCompile & 0x0F);

            if (msgIn == null)
                return false;

            // No paramStr, like Pause
            if (msgIn.Length == 0)
            {
                if (sCmd.cmd == eCMDList.Pause)
                {
                    sCmd.paramCount = 0;
                    return true;
                }
                else
                    return false;
            }

            // Check parameter count, msgIn[0] is for command, parameter start from 1
            switch (sCmd.cmd)
            {
                case eCMDList.SetIICMode:
                case eCMDList.SetChipAddr:
                case eCMDList.SetDelay:
                case eCMDList.IICRead:
                case eCMDList.TestBusRead:
                    sCmd.paramCount = 1;
                    if (msgIn.Length != sCmd.paramCount)      // 1 param
                        return false;
                    break;

                case eCMDList.IICWrite:
                case eCMDList.TestBusWrite:
                case eCMDList.IICBurstRead:
                    sCmd.paramCount = 2;
                    if (msgIn.Length != sCmd.paramCount)      // 2 param
                        return false;
                    break;

                case eCMDList.IICWaitUntil:
                    sCmd.paramCount = 3;
                    if (msgIn.Length != sCmd.paramCount)      // 3 param
                        return false;
                    break;

                case eCMDList.IICReadBitField:      // IICReadBitField RegAddr [x:y], sperate x and y
                case eCMDList.TestBusReadBitField:  // TestBusReadBitField RegAddr [x:y]; sperate x and y
                    sCmd.paramCount = 3;
                    if ((msgIn.Length + 1) != sCmd.paramCount)      // 3 param
                        return false;
                    break;

                case eCMDList.IICSetBitField:       //IICSetBitField RegAddr [x:y] Value; 
                case eCMDList.TestBusSetBitField:    //TestBusSetBitField RegAddr [x:y] Value;
                case eCMDList.IICWaitBitFieldUntil:
                    sCmd.paramCount = 4;
                    if ((msgIn.Length + 1) != sCmd.paramCount)      // 4 param, sperate x and y 
                        return false;
                    break;

                case eCMDList.IICBurstWrite:    // >= 2 param                    
                    sCmd.paramCount = msgIn.Length;
                    if (msgIn.Length < 2)
                        return false;
                    
                    break;

                case eCMDList.IICSetBit:    // >2 params, RegAdd and Bits info. Bit index in 2nd parameter and is sperated by '|' 
                case eCMDList.IICClearBit:
                    if ((msgIn.Length < 2) || (msgIn.Length > (byteCnt_RegData * 8 + 1))) // Max bit count is byteCnt_RegData * 8. 
                        return false;

                    sCmd.paramCount = 2; // bit parmas will generate 1 mask 
                    break;

                default:
                    break;

            }

            // try to decode parameters
            UInt32 tempParam = 0;
            string[] tempParamArray;
            switch (sCmd.cmd)
            {
                case eCMDList.SetIICMode:   // Only support string type parameters
                    if (IICModeDecode(msgIn[0]) == IICMode.None)
                        return false;
                    else
                    {
                        sCmd.paramStr.Add(msgIn[0]);
                    }
                    iicModeForCompile = IICModeDecode(msgIn[0]);
                    break;

                case eCMDList.IICSetBit:        //IICSetBit RegAddr BX1|BX2|...BXn; 
                case eCMDList.IICClearBit:      //IICClearBit RegAddr BX1|BX2|...BXn;                 
                    // RegAddr
                    if (msgIn[0].ToLower().Contains("0x"))  // Hex format
                    {
                        ret &= UInt32.TryParse(msgIn[0].ToLower().Replace("0x", ""), NumberStyles.HexNumber, null, out tempParam);
                    }
                    else
                    {
                        ret &= UInt32.TryParse(msgIn[0], out tempParam);  // Decimal data
                    }

                    sCmd.paramU32.Add(tempParam);
                    sCmd.paramStr.Add(msgIn[0]);
                    // Bit mask generating
                    UInt32 bitMask = 0x0;
                    for (int ix = 1; ix < msgIn.Length; ix++)
                    {
                        ret &= UInt32.TryParse(msgIn[ix].ToUpper().Replace("B", ""), out tempParam);  // Decimal data
                        if (ret)
                        {
                            if (tempParam > (byteCnt_RegData * 8 - 1))
                            {
                                ret = false;
                                break;
                            }
                        }

                        if (ret)
                            bitMask |= (UInt32)(1 << (int)tempParam);
                        else
                            break;
                    }
                    if (ret)
                    {
                        sCmd.paramU32.Add(bitMask);
                        sCmd.paramStr.Add(string.Join("|", msgIn, 1, msgIn.Length - 1));

                    }

                    break;

                case eCMDList.IICSetBitField:       //IICSetBitField RegAddr [x:y] Value; 
                case eCMDList.IICWaitBitFieldUntil: //IICWBFU RegAddr [x:y] TargetValue;
                case eCMDList.IICReadBitField:      //IICReadBitField RegAddr [x:y], sperate x and y
                case eCMDList.TestBusSetBitField:   //TestBusSetBitField RegAddr [x:y] Value;
                case eCMDList.TestBusReadBitField:  //TestBusReadBitField RegAddr [x:y];
                    // RegAddr
                    if (msgIn[0].ToLower().Contains("0x"))  // Hex format
                    {
                        ret &= UInt32.TryParse(msgIn[0].ToLower().Replace("0x", ""), NumberStyles.HexNumber, null, out tempParam);
                    }
                    else
                    {
                        ret &= UInt32.TryParse(msgIn[0], out tempParam);  // Decimal data
                    }

                    sCmd.paramU32.Add(tempParam);
                    sCmd.paramStr.Add(msgIn[0]);

                    // Bit mask generating
                    bitMask = 0x0;
                    tempParamArray = msgIn[1].Replace("[", "").Replace("]", "").Split(':');
                    if (tempParamArray.Length != 2)
                    {
                        ret = false;
                        break;
                    }
                    UInt32 bitx, bity;
                    ret &= UInt32.TryParse(tempParamArray[0].ToUpper().Replace("B", ""), out bitx);  // Decimal data
                    ret &= UInt32.TryParse(tempParamArray[1].ToUpper().Replace("B", ""), out bity);  // Decimal data
                    if (ret)
                    {
                        if ((bitx > (byteCnt_RegData * 8 - 1)) || (bity > (byteCnt_RegData * 8 - 1)))
                        {
                            ret = false;
                            break;
                        }

                        sCmd.paramU32.Add(bitx > bity ? bitx : bity);   //EndBitIndex
                        sCmd.paramStr.Add(string.Format("[{0}:", sCmd.paramU32[1]));

                        sCmd.paramU32.Add(bitx > bity ? bity : bitx);   //StartBitIndex
                        sCmd.paramStr.Add(string.Format("{0}]", sCmd.paramU32[2]));
                    }

                    // BitField Data
                    if ((sCmd.cmd == eCMDList.IICSetBitField) || (sCmd.cmd == eCMDList.IICWaitBitFieldUntil) || 
                        (sCmd.cmd == eCMDList.TestBusSetBitField))
                    {
                        if (msgIn[2].ToLower().Contains("0x"))  // Hex format
                        {
                            ret &= UInt32.TryParse(msgIn[2].ToLower().Replace("0x", ""), NumberStyles.HexNumber, null, out tempParam);
                        }
                        else
                        {
                            ret &= UInt32.TryParse(msgIn[2], out tempParam);  // Decimal data
                        }
                        sCmd.paramU32.Add(tempParam);
                        sCmd.paramStr.Add(msgIn[2]);
                    }

                    break;

                default:    // Other commands, all Numeric parameters                    
                    sCmd.paramStr.Clear();
                    for (int ix_param = 0; ix_param < msgIn.Length; ix_param++)
                    {
                        if (msgIn[ix_param].ToLower().Contains("0x"))  // Hex format
                        {
                            ret &= UInt32.TryParse(msgIn[ix_param].ToLower().Replace("0x", ""), NumberStyles.HexNumber, null, out tempParam);
                        }
                        else
                        {
                            ret &= UInt32.TryParse(msgIn[ix_param], out tempParam);  // Decimal data
                        }                        

                        sCmd.paramU32.Add(tempParam);
                        sCmd.paramStr.Add(msgIn[ix_param]);
                        //sCmd.paramStr.Add(tempParam.ToString());
                    }
                    break;
            }

            return ret;
        }

        private bool ScriptCompile(string msg)
        {
            validCMDList.Clear();
            iicModeForCompile = IICMode.A16D32;

            if ((msg == null) || (msg.Length == 0))
            {
                logWin.AppendLog("None for compiling!");
                return false;
            }

            //validCMDList.Clear();
            int successCnt = 0;
            int errCnt = 0;
            eCMDList cmdType = eCMDList.None;

            string[] msgList = msg.Split('\n');
            string tempStr = string.Empty;

            string[] paramArray;
            logWin.AppendLog(string.Format("\r\n--------- Compile Start: {0} ----------", DateTime.Now.ToString()));
            for (int ix = 0; ix < msgList.Length; ix++)
            {
                if ((msgList[ix].Length == 0) || msgList[ix].StartsWith(@"//") || msgList[ix].StartsWith(@"/*"))  // Empty line or Comment line
                    continue;

                tempStr = msgList[ix];
                if (tempStr.Contains("/"))
                    tempStr = tempStr.Substring(0, msgList[ix].IndexOf('/'));

                if ((tempStr.Contains(";"))) // remove all string after ";"
                    tempStr = tempStr.Substring(0, msgList[ix].IndexOf(';'));

                //paramArray = msgList[ix].Trim().Split(" ,".ToCharArray());
                paramArray = tempStr.Trim().Split(new char[] { ' ', ',', '|' }, StringSplitOptions.RemoveEmptyEntries);
                //if (paramArray.Length < 2)
                //{
                //    this.logWin.AppendLog(string.Format("Wrong format detected at line {0}", ix + 1), Color.Red);
                //    continue;
                //}


                cmdType = CommandDecode(paramArray[0]);
                if (cmdType == eCMDList.Unknown)
                {
                    this.logWin.AppendLog(string.Format("{0} command in line {1}", eCMDList.Unknown.ToString(), ix), Color.Red);
                    continue;
                }

                ScriptCMD tempScriptCMD = new ScriptCMD();
                tempScriptCMD.cmd = cmdType;
                tempScriptCMD.lineNo = ix + 1;
                tempScriptCMD.paramU32 = new List<uint> { };
                tempScriptCMD.paramStr = new List<string> { };

                // Check Parameters
                bool ret = ParameterCheck(paramArray.Skip(1).Take(paramArray.Length - 1).ToArray(), ref tempScriptCMD);

                // Adde to valid command list at the end
                if (ret)
                {
                    successCnt++;
                    validCMDList.Add(tempScriptCMD);
                }
                else
                {
                    errCnt++;
                    this.logWin.AppendLog(string.Format("Parameter error in line {0}", ix + 1), Color.Red);
                }

            }

            logWin.AppendLog(string.Format("---------  Success {0}; Error {1} ----------\r\n", successCnt, errCnt));

            return (errCnt > 0) ? false : true;
        }

        #region Command Operation Func, Do Not varify if parameter reasonable which judge during compiling.
        
        private void Do_SetIICMode(ScriptCMD sCmd)
        {
            this.currentI2CMode = IICModeDecode(sCmd.paramStr[0]);
            PrintCMDLog(sCmd, true) ;
        }

        private bool Do_SetChipAddr(ScriptCMD sCmd)
        {
            byte tempChipAddr = (byte)sCmd.paramU32[0];

            if (tempChipAddr == 0 || tempChipAddr > 127)
            {
                PrintCMDLog(sCmd, false);
                return false;
            }
            else
            {
                PrintCMDLog(sCmd, true);
                this.currentChipAddr = (byte)(tempChipAddr << 1);
                return true;
            }
        }

        private void Do_SetDelay(ScriptCMD sCmd) 
        {
            int mSec = sCmd.paramU32[0] > int.MaxValue ? int.MaxValue : (int)sCmd.paramU32[0];

            Thread.Sleep(mSec);
            PrintCMDLog(sCmd, true);
        }

        private void Do_Paused(ScriptCMD sCmd)
        {
            ChangeStatus = eExcuteStatus.Paused;
            PrintCMDLog(sCmd, true);
        }

        private bool Do_IICSingleWrite(ScriptCMD sCmd)
        {
            bool ret = commDev.IICWrite(this.currentChipAddr, (object)sCmd.paramU32[0], (object)sCmd.paramU32[1], currentI2CMode);

            PrintCMDLog(sCmd, ret);

            return ret;
        }

        private bool Do_IICSingleRead(ScriptCMD sCmd)
        {
            object rdData = 0;
            int byteCnt_PerData = (byte)currentI2CMode & 0x0F;
            bool ret = commDev.IICRead(this.currentChipAddr, (object)sCmd.paramU32[0], out rdData, currentI2CMode);
            PrintCMDLog(sCmd, ret);

            if (ret)
                PrintInfo(String.Format("Read Value:0x{0}\r\n", (Convert.ToUInt32(rdData)).ToString(String.Format("X{0}", 2 * byteCnt_PerData)))); 

            return ret;

        }

        private bool Do_IICBurstWrite(ScriptCMD sCmd)
        {
            // 1st param is RegAddr, RegData start from 2nd param
            object[] wrData = new object[sCmd.paramCount - 1];
            for (int ix = 1; ix < sCmd.paramCount; ix++)
            {
                wrData[ix - 1] = (object)sCmd.paramU32[ix];
            }

            bool ret = commDev.IICWrite_Burst(currentChipAddr, (object)sCmd.paramU32[0], wrData, currentI2CMode);

            PrintCMDLog(sCmd, ret);
            return ret;
        }

        private bool Do_IICBurstRead(ScriptCMD sCmd)
        {
            int byteCnt_RegAddr = ((byte)currentI2CMode >> 4) & 0x0F;
            //int byteCnt_RegData = ((byte)currentI2CMode & 0x0F) * RegData.Length;
            int byteCnt_PerData = (byte)currentI2CMode & 0x0F;

            // 1st param is RegAddr, RegData start from 2nd param
            object[] rdData = new object[sCmd.paramU32[1]];
            

            bool ret = commDev.IICRead_Burst(currentChipAddr, (object)sCmd.paramU32[0], out rdData, rdData.Length ,currentI2CMode);
            PrintCMDLog(sCmd, ret);

            if (ret)
            {
                string dataLog = String.Format("Burst Read from Reg0x{0}, RegData: ", sCmd.paramStr[0]);
                for (int ix = 0; ix < rdData.Length; ix++)
                {
                    UInt32 tempData = Convert.ToUInt32(rdData[ix]);
                    dataLog += String.Format("0x{0}, ", tempData.ToString(string.Format("X{0}", byteCnt_PerData * 2)));
                }

                PrintInfo(dataLog);
            }

            return ret;
        }

        private bool Do_IICSetBit(ScriptCMD sCmd)
        {
            object rdData = 0;
            UInt32 wrData = 0;
            bool ret = commDev.IICRead(this.currentChipAddr, (object)sCmd.paramU32[0], out rdData, currentI2CMode);
            if(!ret) 
            {
                return ret;
            }
            PrintInfo(string.Format("IIC Read: Reg0x{0} = 0x{1}", sCmd.paramU32[0].ToString("X2"), Convert.ToUInt32(rdData).ToString("X2")));

            // 2nd param is the mask
            wrData = Convert.ToUInt32(rdData) | sCmd.paramU32[1];
            ret = commDev.IICWrite(this.currentChipAddr, (object)sCmd.paramU32[0], (object)wrData, currentI2CMode);
            PrintInfo(string.Format("IIC Write: Reg0x{0} = 0x{1}", sCmd.paramU32[0].ToString("X2"), wrData.ToString("X2")));

            PrintCMDLog(sCmd, ret);

            return ret;
        }

        private bool Do_IICSetBitField(ScriptCMD sCmd)
        {
            //IICSetBitField RegAddr [x:y] Value; 
            // Parameter sequence: RegAddr EndBitIndex StartBitIndex BFValue
            object rdData = 0;
            UInt32 wrData = 0;
            bool ret = commDev.IICRead(this.currentChipAddr, (object)sCmd.paramU32[0], out rdData, currentI2CMode);
            if (!ret)
            {
                return ret;
            }

            PrintInfo(string.Format("IIC Read: Reg0x{0} = 0x{1}", sCmd.paramU32[0].ToString("X2"), Convert.ToUInt32(rdData).ToString("X2")));

            // 2nd param is the mask
            UInt32 endBitIx = sCmd.paramU32[1];
            UInt32 startBitIx = sCmd.paramU32[2];
            //UInt32 bfMask = (UInt32)(((1 << (int)(endBitIx + 1)) - 1) - ((1 << (int)startBitIx) - 1));
            UInt32 bfMask = (UInt32)(Math.Pow(2, endBitIx + 1) - Math.Pow(2, startBitIx));

            //Console.WriteLine(((1 << (int)(endBitIx + 1)) - 1).ToString("X2"));
            //Console.WriteLine(((1 << (int)startBitIx) - 1).ToString("X2"));

            //Console.WriteLine(((UInt32)(Math.Pow(2, endBitIx + 1) - 1)).ToString("X2"));
            //Console.WriteLine(((UInt32)(Math.Pow(2, startBitIx) - 1)).ToString("X2"));

            
            wrData = (Convert.ToUInt32(rdData) & ~bfMask) | ((sCmd.paramU32[3] << (int)startBitIx) & bfMask);
            ret = commDev.IICWrite(this.currentChipAddr, (object)sCmd.paramU32[0], (object)wrData, currentI2CMode);

            PrintInfo(string.Format("IIC Write: Reg0x{0} = 0x{1}; BF Mask: 0x{2}", sCmd.paramU32[0].ToString("X2"), wrData.ToString("X2"), bfMask.ToString("X2")));

            PrintCMDLog(sCmd, ret);

            return ret;
        }

        private bool Do_IICReadBitField(ScriptCMD sCmd)
        {
            //IICReadBitField RegAddr [x:y]; 
            // Parameter sequence: RegAddr EndBitIndex StartBitIndex
            object rdData = 0;
            UInt32 bfValue = 0;
            bool ret = commDev.IICRead(this.currentChipAddr, (object)sCmd.paramU32[0], out rdData, currentI2CMode);
            if (!ret)
            {
                return ret;
            }

            PrintCMDLog(sCmd, ret);
            PrintInfo(string.Format("IIC Read: Reg0x{0} = 0x{1}", sCmd.paramU32[0].ToString("X2"), Convert.ToUInt32(rdData).ToString("X2")));

            // 2nd param is the mask
            UInt32 endBitIx = sCmd.paramU32[1];
            UInt32 startBitIx = sCmd.paramU32[2];
            //UInt32 bfMask = (UInt32)(((1 << (int)(endBitIx + 1)) - 1) - ((1 << (int)startBitIx) - 1));
            UInt32 bfMask = (UInt32)(Math.Pow(2, endBitIx + 1) - Math.Pow(2, startBitIx));

            //Console.WriteLine(((1 << (int)(endBitIx + 1)) - 1).ToString("X2"));
            //Console.WriteLine(((1 << (int)startBitIx) - 1).ToString("X2"));

            //Console.WriteLine(((UInt32)(Math.Pow(2, endBitIx + 1) - 1)).ToString("X2"));
            //Console.WriteLine(((UInt32)(Math.Pow(2, startBitIx) - 1)).ToString("X2"));
            bfValue = (UInt32)((Convert.ToUInt32(rdData) & bfMask) >> (int)startBitIx);

            PrintInfo(string.Format("IIC Read: Reg0x{0}{1} = 0x{2}; BF Mask: 0x{3}\r\n", sCmd.paramU32[0].ToString("X2"), sCmd.paramStr[1] + sCmd.paramStr[2], bfValue.ToString("X2"), bfMask.ToString("X2")));
            return ret;
        }

        private bool Do_IICClearBit(ScriptCMD sCmd) 
        {
            object rdData = 0;
            UInt32 wrData = 0;
            bool ret = commDev.IICRead(this.currentChipAddr, (object)sCmd.paramU32[0], out rdData, currentI2CMode);
            if (!ret)
            {
                return ret;
            }
            PrintInfo(string.Format("IIC Read: Reg0x{0} = 0x{1}", sCmd.paramU32[0].ToString("X2"), Convert.ToUInt32(rdData).ToString("X2")));

            // 2nd param is the mask
            wrData = Convert.ToUInt32(rdData) & (~sCmd.paramU32[1]);
            ret = commDev.IICWrite(this.currentChipAddr, (object)sCmd.paramU32[0], (object)wrData, currentI2CMode);
            PrintInfo(string.Format("IIC Write: Reg0x{0} = 0x{1}", sCmd.paramU32[0].ToString("X2"), wrData.ToString("X2")));

            PrintCMDLog(sCmd, ret);
            return ret;
        }

        private bool Do_IICWaitUntil(ScriptCMD sCmd)
        {
            object rdData = 0;
            int byteCnt_PerData = (byte)currentI2CMode & 0x0F;
            int waitTime = 100;   // 100ms
            int maxRetryCnt = 20;  // Total time is 100*20 = 2Sec

            UInt32 mask = sCmd.paramU32[2];
            UInt32 targetRegData = sCmd.paramU32[1] & mask;
            UInt32 readRegData = 0;

            bool ret;

            do
            {
                ret = commDev.IICRead(this.currentChipAddr, (object)sCmd.paramU32[0], out rdData, currentI2CMode);
                if (ret == false)
                {
                    break;
                }
                else
                {
                    readRegData = Convert.ToUInt32(rdData) & mask;
                    if (targetRegData == readRegData)
                        break;
                }

                Thread.Sleep(waitTime);

                //if (maxRetryCnt % 10 == 0)
                PrintInfo(String.Format("Timeout countdown:{0}", maxRetryCnt));

                //ret = commDev.IICWrite(this.currentChipAddr, (object)sCmd.paramU32[0], (object)sCmd.paramU32[1], currentI2CMode);

            } while (--maxRetryCnt > 0);

            // if timeout, will return failed
            if (maxRetryCnt == 0)
                ret = false;

            PrintCMDLog(sCmd, ret);

            return ret;
        }

        private bool Do_IICWaitBFUntil(ScriptCMD sCmd)
        {
            //IICWaitBFUntil RegAddr [x:y] TargetValue; 
            // Parameter sequence: RegAddr EndBitIndex StartBitIndex TargetValue

            object rdData = 0;
            int byteCnt_PerData = (byte)currentI2CMode & 0x0F;
            int waitTime = 100;   // 100ms
            int maxRetryCnt = 20;  // Total time is 100*20 = 2Sec

            // 2nd param is the mask
            UInt32 endBitIx = sCmd.paramU32[1];
            UInt32 startBitIx = sCmd.paramU32[2];
            UInt32 bfMask = (UInt32)(Math.Pow(2, endBitIx + 1) - Math.Pow(2, startBitIx));


            UInt32 targetRegData = sCmd.paramU32[3] << (int)startBitIx;
            UInt32 readRegData = 0;

            bool ret;

            do
            {
                ret = commDev.IICRead(this.currentChipAddr, (object)sCmd.paramU32[0], out rdData, currentI2CMode);
                if (ret == false)
                {
                    break;
                }
                else
                {
                    readRegData = Convert.ToUInt32(rdData) & bfMask;
                    if (targetRegData == readRegData)
                        break;
                }

                Thread.Sleep(waitTime);

                PrintInfo(String.Format("Timeout countdown:{0}", maxRetryCnt));

                //ret = commDev.IICWrite(this.currentChipAddr, (object)sCmd.paramU32[0], (object)sCmd.paramU32[1], currentI2CMode);

            } while (--maxRetryCnt > 0);

            // if timeout, will return failed
            if (maxRetryCnt == 0)
                ret = false;

            PrintCMDLog(sCmd, ret);

            return ret;
        }

        private bool Do_TestBusWrite(ScriptCMD sCmd)
        {
            /* 0x9050[31:2] - reserved
             * 0x9050[1]    - phy_testclk
             * 0x9050[0]    - phy_testclr
             * 
             * 0x9054[31:17] - reserved
             * 0x9054[16]    - phy_testen
             * 0x9054[15:8]  - phy_testdout
             * 0x9054[7:0]   - phy_testdin
             */

            /* Test bus write method
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * IICSB 0x9054 B16 //en=1
             * IICSB 0x9050 B1  //clk=1
             * IICSBF 0x9054 [7:0] 0x00 //din=0
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * IICSBF 0x9054 [7:0] 0x0C //din= MSB
             * IICSB 0x9050 B1  //clk=1
             * 
             * //Step2, write address 8 bits LSB
             * IICCB 0x9050 B1  //clk = 0
             * IICSB 0x9054 B16 //en=1
             * IICSB 0x9050 B1  //clk=1
             * IICSBF 0x9054 [7:0] 0x0A //din= LSB
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * 
             * //Step3, wirte 8bits data
             * IICSBF 0x9054 [7:0] 0x55 //din= data
             * IICSB 0x9050 B1  //clk=1
             */
            bool ret = false;
            UInt16 regAddr_0x9050 = 0x9050;
            UInt16 regAddr_0x9054 = 0x9054;
            object regData_0x9050 = 0;
            object regData_0x9054 = 0;
            UInt32 mask_B1 = 1 << 1;
            UInt32 mask_B0 = 1;
            UInt32 mask_B16 = 1 << 16;
            UInt32 mask_dint = 0xFF;

            // Read back Reg0x9050 and Reg0x9054 for bit operations below
            ret = commDev.IICRead(this.currentChipAddr, regAddr_0x9050, out regData_0x9050, currentI2CMode);
            if (!ret) return ret;
            ret = commDev.IICRead(this.currentChipAddr, regAddr_0x9054, out regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            #region Prepare for testbus access
            /*  IICSB 0x9050 B0
             *  Delay 1
             *  IICCB 0x9050 B0 */
            //regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B0;     // clr = 1
            //ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            //if (!ret) return ret;

            //Thread.Sleep(1);

            //regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B0;     // clr = 0
            //ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            //if (!ret) return ret;

            #endregion

            #region  Step1
            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if(!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_B16;    // en = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if(!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) | mask_B16;    // en = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_dint;    // din = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_B16;    // en = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = (Convert.ToUInt32(regData_0x9054) & ~mask_dint) | ((sCmd.paramU32[0] >> 8) & mask_dint);    // din = targetRegAddr_MSB
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            #endregion Step1

            #region  Step2
            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) | mask_B16;    // en = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = (Convert.ToUInt32(regData_0x9054) & ~mask_dint) | (sCmd.paramU32[0] & mask_dint);    // din = targetRegAddr_LSB
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_B16;    // en = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            #endregion Step2

            #region  Step3
            regData_0x9054 = (Convert.ToUInt32(regData_0x9054) & ~mask_dint) | (sCmd.paramU32[1] & mask_dint);    // din = targetData
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;
            #endregion Step3

            ret = commDev.IICRead(this.currentChipAddr, regAddr_0x9054, out regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            PrintCMDLog(sCmd, ret);

            return true;
        }

        private bool Do_TestBusRead(ScriptCMD sCmd)
        {
            /* 0x9050[31:2] - reserved
            * 0x9050[1]    - phy_testclk
            * 0x9050[0]    - phy_testclr
            * 
            * 0x9054[31:17] - reserved
            * 0x9054[16]    - phy_testen
            * 0x9054[15:8]  - phy_testdout
            * 0x9054[7:0]   - phy_testdin
            */

            /* Test bus write method
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * IICSB 0x9054 B16 //en=1
             * IICSB 0x9050 B1  //clk=1
             * IICSBF 0x9054 [7:0] 0x00 //din=0
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * IICSBF 0x9054 [7:0] 0x0C //din= MSB
             * IICSB 0x9050 B1  //clk=1
             * 
             * //Step2, write address 8 bits LSB
             * IICCB 0x9050 B1  //clk = 0
             * IICSB 0x9054 B16 //en=1
             * IICSB 0x9050 B1  //clk=1
             * IICSBF 0x9054 [7:0] 0x0A //din= LSB
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * 
             * //Step3, wirte 8bits data - Do Not Need
             * //IICSBF 0x9054 [7:0] 0x55 //din= data
             * //IICSB 0x9050 B1  //clk=1
             * 
             * //Step4, read 8bits data
             * IICRdBF 0x9054 [15:8]
             */
            bool ret = false;
            UInt16 regAddr_0x9050 = 0x9050;
            UInt16 regAddr_0x9054 = 0x9054;
            object regData_0x9050 = 0;
            object regData_0x9054 = 0;
            UInt32 tempData = 0;
            UInt32 mask_B1 = 1 << 1;
            UInt32 mask_B0 = 1;
            UInt32 mask_B16 = 1 << 16;
            UInt32 mask_dout = 0xFF00;
            UInt32 mask_dint = 0xFF;

            // Read back Reg0x9050 and Reg0x9054 for bit operations below
            ret = commDev.IICRead(this.currentChipAddr, regAddr_0x9050, out regData_0x9050, currentI2CMode);
            if (!ret) return ret;
            ret = commDev.IICRead(this.currentChipAddr, regAddr_0x9054, out regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            #region Prepare for testbus access
            /*  IICSB 0x9050 B0
             *  Delay 1
             *  IICCB 0x9050 B0 */
            //regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B0;     // clr = 1
            //ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            //if (!ret) return ret;

            //Thread.Sleep(1);

            //regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B0;     // clr = 0
            //ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            //if (!ret) return ret;

            #endregion

            #region  Step1
            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_B16;    // en = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) | mask_B16;    // en = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_dint;    // din = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_B16;    // en = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = (Convert.ToUInt32(regData_0x9054) & ~mask_dint) | ((sCmd.paramU32[0] >> 8) & mask_dint);    // din = targetRegAddr_MSB
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            #endregion Step1

            #region  Step2
            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) | mask_B16;    // en = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = (Convert.ToUInt32(regData_0x9054) & ~mask_dint) | (sCmd.paramU32[0] & mask_dint);    // din = targetRegAddr_LSB
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_B16;    // en = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            #endregion Step2

            #region  Step3 - DO NOT Need
            //tempData = (Convert.ToUInt32(regData_0x9054) & ~mask_dint) | (sCmd.paramU32[1] & mask_dint);    // din = targetData
            //ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, tempData, currentI2CMode);
            //if (!ret) return ret;

            //tempData = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            //ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, tempData, currentI2CMode);
            //if (!ret) return ret;
            #endregion Step3

            #region Step4
            ret = commDev.IICRead(this.currentChipAddr, regAddr_0x9054, out regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            PrintCMDLog(sCmd, ret);

            tempData = (Convert.ToUInt32(regData_0x9054) & mask_dout) >> 8;
            if (ret)
                PrintInfo(String.Format("Test Bus Read Value:0x{0}\r\n", tempData.ToString(String.Format("X2"))));
            #endregion Step4

            return true;
        }

        /// <summary>
        /// TestBusSetBitField RegAddr [x:y] Value; 
        /// Parameter sequence: RegAddr EndBitIndex StartBitIndex BFValue
        /// </summary>
        /// <param name="sCmd"></param>
        /// <returns></returns>
        private bool Do_TestBusSetBitField(ScriptCMD sCmd)
        {
            /* 0x9050[31:2] - reserved
             * 0x9050[1]    - phy_testclk
             * 0x9050[0]    - phy_testclr
             * 
             * 0x9054[31:17] - reserved
             * 0x9054[16]    - phy_testen
             * 0x9054[15:8]  - phy_testdout
             * 0x9054[7:0]   - phy_testdin
             */

            /* Test bus write method
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * IICSB 0x9054 B16 //en=1
             * IICSB 0x9050 B1  //clk=1
             * IICSBF 0x9054 [7:0] 0x00 //din=0
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * IICSBF 0x9054 [7:0] 0x0C //din= MSB
             * IICSB 0x9050 B1  //clk=1
             * 
             * //Step2, write address 8 bits LSB
             * IICCB 0x9050 B1  //clk = 0
             * IICSB 0x9054 B16 //en=1
             * IICSB 0x9050 B1  //clk=1
             * IICSBF 0x9054 [7:0] 0x0A //din= LSB
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * 
             * //Step3, read 8bits data
             * IICRdBF 0x9054 [15:8]  //dout

             * //Step4, wirte 8bits data with BF mask
             * IICSBF 0x9054 [7:0] (dout&bfMask)|targetData  //din= targetData
             * IICSB 0x9050 B1  //clk=1
             */
            bool ret = false;
            UInt16 regAddr_0x9050 = 0x9050;
            UInt16 regAddr_0x9054 = 0x9054;
            object regData_0x9050 = 0;
            object regData_0x9054 = 0;
            UInt32 mask_B1 = 1 << 1;
            UInt32 mask_B0 = 1;
            UInt32 mask_B16 = 1 << 16;
            UInt32 mask_dint = 0xFF;
            UInt32 mask_dout = 0xFF00;

            // Read back Reg0x9050 and Reg0x9054 for bit operations below
            ret = commDev.IICRead(this.currentChipAddr, regAddr_0x9050, out regData_0x9050, currentI2CMode);
            if (!ret) return ret;
            ret = commDev.IICRead(this.currentChipAddr, regAddr_0x9054, out regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            #region Prepare for testbus access
            /*  IICSB 0x9050 B0
             *  Delay 1
             *  IICCB 0x9050 B0 */
            //regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B0;     // clr = 1
            //ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            //if (!ret) return ret;

            //Thread.Sleep(1);

            //regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B0;     // clr = 0
            //ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            //if (!ret) return ret;

            #endregion

            #region  Step1
            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_B16;    // en = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) | mask_B16;    // en = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_dint;    // din = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_B16;    // en = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = (Convert.ToUInt32(regData_0x9054) & ~mask_dint) | ((sCmd.paramU32[0] >> 8) & mask_dint);    // din = targetRegAddr_MSB
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            #endregion Step1

            #region  Step2
            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) | mask_B16;    // en = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = (Convert.ToUInt32(regData_0x9054) & ~mask_dint) | (sCmd.paramU32[0] & mask_dint);    // din = targetRegAddr_LSB
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_B16;    // en = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            #endregion Step2

            #region Step3
            ret = commDev.IICRead(this.currentChipAddr, regAddr_0x9054, out regData_0x9054, currentI2CMode);
            if (!ret) return ret;
            #endregion Step3

            #region  Step4
            // 2nd param is the mask
            UInt32 endBitIx = sCmd.paramU32[1];
            UInt32 startBitIx = sCmd.paramU32[2];
            UInt32 bfMask = (UInt32)(Math.Pow(2, endBitIx + 1) - Math.Pow(2, startBitIx));

            UInt32 tempData = (Convert.ToUInt32(regData_0x9054) & mask_dout) >> 8;  // read back current regData
            PrintInfo(string.Format("TestBus - Read: Reg0x{0} = 0x{1}", sCmd.paramU32[0].ToString("X2"), tempData.ToString("X2")));
            tempData = (tempData & ~bfMask) | ((sCmd.paramU32[3] << (int)startBitIx) & bfMask); // calc target bf value

            regData_0x9054 = (Convert.ToUInt32(regData_0x9054) & ~mask_dint) | (tempData & mask_dint);    // din = targetData
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            PrintInfo(string.Format("TestBus - Write: Reg0x{0} = 0x{1}; BF Mask: 0x{2}", sCmd.paramU32[0].ToString("X2"), tempData.ToString("X2"), bfMask.ToString("X2")));

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;
            #endregion Step4

            PrintCMDLog(sCmd, ret);

            return true;
        }

        private bool Do_TestBusReadBitField(ScriptCMD sCmd)
        {
            /* 0x9050[31:2] - reserved
            * 0x9050[1]    - phy_testclk
            * 0x9050[0]    - phy_testclr
            * 
            * 0x9054[31:17] - reserved
            * 0x9054[16]    - phy_testen
            * 0x9054[15:8]  - phy_testdout
            * 0x9054[7:0]   - phy_testdin
            */

            /* Test bus write method
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * IICSB 0x9054 B16 //en=1
             * IICSB 0x9050 B1  //clk=1
             * IICSBF 0x9054 [7:0] 0x00 //din=0
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * IICSBF 0x9054 [7:0] 0x0C //din= MSB
             * IICSB 0x9050 B1  //clk=1
             * 
             * //Step2, write address 8 bits LSB
             * IICCB 0x9050 B1  //clk = 0
             * IICSB 0x9054 B16 //en=1
             * IICSB 0x9050 B1  //clk=1
             * IICSBF 0x9054 [7:0] 0x0A //din= LSB
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * 
             * //Step3, wirte 8bits data - Do Not Need
             * //IICSBF 0x9054 [7:0] 0x55 //din= data
             * //IICSB 0x9050 B1  //clk=1
             * 
             * //Step4, read 8bits data
             * IICRdBF 0x9054 [15:8]
             */
            bool ret = false;
            UInt16 regAddr_0x9050 = 0x9050;
            UInt16 regAddr_0x9054 = 0x9054;
            object regData_0x9050 = 0;
            object regData_0x9054 = 0;
            UInt32 tempData = 0;
            UInt32 mask_B1 = 1 << 1;
            UInt32 mask_B0 = 1;
            UInt32 mask_B16 = 1 << 16;
            UInt32 mask_dout = 0xFF00;
            UInt32 mask_dint = 0xFF;

            // Read back Reg0x9050 and Reg0x9054 for bit operations below
            ret = commDev.IICRead(this.currentChipAddr, regAddr_0x9050, out regData_0x9050, currentI2CMode);
            if (!ret) return ret;
            ret = commDev.IICRead(this.currentChipAddr, regAddr_0x9054, out regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            #region Prepare for testbus access
            /*  IICSB 0x9050 B0
             *  Delay 1
             *  IICCB 0x9050 B0 */
            //regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B0;     // clr = 1
            //ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            //if (!ret) return ret;

            //Thread.Sleep(1);

            //regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B0;     // clr = 0
            //ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            //if (!ret) return ret;

            #endregion

            #region  Step1
            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_B16;    // en = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) | mask_B16;    // en = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_dint;    // din = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_B16;    // en = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = (Convert.ToUInt32(regData_0x9054) & ~mask_dint) | ((sCmd.paramU32[0] >> 8) & mask_dint);    // din = targetRegAddr_MSB
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            #endregion Step1

            #region  Step2
            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) | mask_B16;    // en = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = (Convert.ToUInt32(regData_0x9054) & ~mask_dint) | (sCmd.paramU32[0] & mask_dint);    // din = targetRegAddr_LSB
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B1;     // clk = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, regData_0x9050, currentI2CMode);
            if (!ret) return ret;

            regData_0x9054 = Convert.ToUInt32(regData_0x9054) & ~mask_B16;    // en = 0
            ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            #endregion Step2

            #region  Step3 - DO NOT Need
            //tempData = (Convert.ToUInt32(regData_0x9054) & ~mask_dint) | (sCmd.paramU32[1] & mask_dint);    // din = targetData
            //ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9054, tempData, currentI2CMode);
            //if (!ret) return ret;

            //tempData = Convert.ToUInt32(regData_0x9050) | mask_B1;     // clk = 1
            //ret = commDev.IICWrite(this.currentChipAddr, regAddr_0x9050, tempData, currentI2CMode);
            //if (!ret) return ret;
            #endregion Step3

            #region Step4
            ret = commDev.IICRead(this.currentChipAddr, regAddr_0x9054, out regData_0x9054, currentI2CMode);
            if (!ret) return ret;

            PrintCMDLog(sCmd, ret);

            tempData = (Convert.ToUInt32(regData_0x9054) & mask_dout) >> 8;
            if (ret)
                PrintInfo(String.Format("Test Bus Read : Reg0x{0} = 0x{1}", sCmd.paramU32[0].ToString("X2"), tempData.ToString(String.Format("X2"))));

            // 1-2 param is the mask
            UInt32 endBitIx = sCmd.paramU32[1];
            UInt32 startBitIx = sCmd.paramU32[2];
            UInt32 bfMask = (UInt32)(Math.Pow(2, endBitIx + 1) - Math.Pow(2, startBitIx));

            tempData = (UInt32)((tempData & bfMask) >> (int)startBitIx);

            PrintInfo(string.Format("Test Bus Read: Reg0x{0}{1} = 0x{2}; BF Mask: 0x{3}\r\n", sCmd.paramU32[0].ToString("X2"), sCmd.paramStr[1] + sCmd.paramStr[2], tempData.ToString("X2"), bfMask.ToString("X2")));

            #endregion Step4
           
            return ret;
        }

        #endregion Command Operation Func

        #endregion Funcs

        #region Events

        private void btn_Script_load_Click(object sender, EventArgs e)
        {
            try
            {
                OpenFileDialog openfiledlg = new OpenFileDialog();
                openfiledlg.Title = "Please choose the script file to be loaded...";
                openfiledlg.Filter = "Script file(*.script)|*.script|Config file(*.cfg)|*.cfg|Text file(*.txt)|*.txt";
                openfiledlg.RestoreDirectory = true;
                string filename = "";
                if (openfiledlg.ShowDialog() == DialogResult.OK)
                {
                    filename = openfiledlg.FileName;
                }
                else
                    return;

                this.richtxt_ScriptView.Text = string.Empty;
                //this.richtxt_ScriptView.SelectionColor = Color.Black;
                StreamReader sr = new StreamReader(filename);
                this.richtxt_ScriptView.Text = sr.ReadToEnd();
                sr.Close();

                this.richtxt_ScriptView.SelectionColor = Color.Black;

                //this.text_Srcipt_Name.Text = System.IO.Path.GetFileName(filename);
                this.lbl_ScriptPath.Text = filename;

                RefreshWholeTextFormat(this.richtxt_ScriptView);
            }
            catch
            {
                MessageBox.Show("Load script file failed, please choose correct file!");
            }
        }

        private void btn_Compile_Click(object sender, EventArgs e)
        {
            ScriptCompile(this.richtxt_ScriptView.Text);
        }

        private void btn_Script_Save_Click(object sender, EventArgs e)
        {
            try
            {
               string filename = this.lbl_ScriptPath.Text;

                if (File.Exists(filename))
                {
                    if (MessageBox.Show("文件已存在，确认覆盖？", "文件保存", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
                        return;

                    if (filename.Contains(".cfg"))
                    {
                        filename = filename.Replace(".cfg", ".script");
                        this.lbl_ScriptPath.Text = filename;
                    }

                    StreamWriter sw = File.CreateText(filename);

                    sw.Write(this.richtxt_ScriptView.Text);
                    sw.Close();

                    PrintInfo(string.Format("Saved to {0}", filename));
                }
                else 
                {
                    btn_SaveAs_Click(null, null);
                }
            }
            catch
            {
                MessageBox.Show("Save script file failed!");
            }
        }

        private void btn_SaveAs_Click(object sender, EventArgs e)
        {
            try
            {
                SaveFileDialog savefiledlg = new SaveFileDialog();
                savefiledlg.Title = "Saving script command...";
                savefiledlg.Filter = "Script file(*.script)|*.script|Text file(*.txt)|*.txt";
                savefiledlg.RestoreDirectory = true;
                string filename = "";
                if (savefiledlg.ShowDialog() == DialogResult.OK)
                {
                    filename = savefiledlg.FileName;
                }
                else
                    return;

                StreamWriter sw = File.CreateText(filename);
                /* script Data */
                sw.Write(this.richtxt_ScriptView.Text);

                sw.Close();

                // Updated current file name
                this.lbl_ScriptPath.Text = filename;
                PrintInfo(string.Format("Saved to {0}", filename));
            }
            catch(Exception ex)
            {
                MessageBox.Show("Save script file failed! Error:{0}", ex.Message);
            }
        }

        int ix_processingCMD = 0;
        private void btn_Script_Excute_Click(object sender, EventArgs e)
        {
            if (excuteStatus == eExcuteStatus.Stopped)
            {
                if (!ScriptCompile(this.richtxt_ScriptView.Text))
                {
                    PrintErr("Compile failed, Abort!");
                    return;
                }
            }
            // if break with puased command, then start from the next cmd of breakpoint
            int ix = (excuteStatus == eExcuteStatus.Paused) ? (ix_processingCMD + 1) : 0;
            ChangeStatus = eExcuteStatus.Running;
            this.btn_Script_Excute.Refresh();
            for(; ix < validCMDList.Count; ix++) 
            {
                switch(validCMDList[ix].cmd)
                {
                    case eCMDList.SetIICMode:
                        Do_SetIICMode(validCMDList[ix]);
                        break;

                    case eCMDList.SetChipAddr:
                        if (!Do_SetChipAddr(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.SetDelay:
                        Do_SetDelay(validCMDList[ix]);
                        break;

                    case eCMDList.Pause:
                        ix_processingCMD = ix;
                        Do_Paused(validCMDList[ix]);
                        return;
                        //break;

                    case eCMDList.IICWrite:
                        if(!Do_IICSingleWrite(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.IICRead:
                        if(!Do_IICSingleRead(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.IICBurstWrite:
                        if (!Do_IICBurstWrite(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.IICBurstRead:
                        if(!Do_IICBurstRead(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.IICSetBit:
                        if(!Do_IICSetBit(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.IICSetBitField:
                        if (!Do_IICSetBitField(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.IICReadBitField:
                        if (!Do_IICReadBitField(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.IICClearBit:
                        if(!Do_IICClearBit(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.IICWaitUntil:
                        if(!Do_IICWaitUntil(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.IICWaitBitFieldUntil:
                        if (!Do_IICWaitBFUntil(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.TestBusWrite:
                        if (!Do_TestBusWrite(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.TestBusRead:
                    if (!Do_TestBusRead(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.TestBusSetBitField:
                        if (!Do_TestBusSetBitField(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;

                    case eCMDList.TestBusReadBitField:
                        if (!Do_TestBusReadBitField(validCMDList[ix]))
                        {
                            ChangeStatus = eExcuteStatus.Stopped;
                            return;
                        }
                        break;


                    default:
                        break;

                }
            }

            ChangeStatus = eExcuteStatus.Stopped;
            // end
        }

        #region Line Number
        string historyText = string.Empty;
        private void richtxt_ScriptView_TextChanged(object sender, EventArgs e)
        {
            UpdateLableRowIndex();

            //this.historyText = richtxt_ScriptView.Text;

            //RefreshWholeTextFormat(this.richtxt_ScriptView);
        }

        private void richtxt_ScriptView_VScroll(object sender, EventArgs e)
        {
            UpdateLableRowIndex();
        }

        private void richtxt_ScriptView_Resize(object sender, EventArgs e)
        {
            UpdateLableRowIndex();
        }

        private void richtxt_ScriptView_FontChanged(object sender, EventArgs e)
        {
            //UpdateLableRowIndex();
        }


        #endregion

        private void btn_saveLog_Click(object sender, EventArgs e)
        {
            string logPath = Environment.CurrentDirectory + "\\log";
            try
            {
                if (!Directory.Exists(logPath))
                    Directory.CreateDirectory(logPath);

                logPath += "\\log_" + DateTime.Now.ToString("d").Replace('/', '-') + ".log";

                StreamWriter sw = new StreamWriter(logPath, true);
                sw.Write(this.logWin.Log);
                sw.Close();
            }
            catch (Exception ex) { MessageBox.Show(ex.Message); }
        }

        private void cmb_IICMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            IICMode _iicMode = IICModeDecode(this.cmb_IICMode.SelectedItem.ToString());
            int bitwidth_RegAddr = (((byte)_iicMode >> 4) & 0x0F) * 8;
            int bitwidth_RegData = ((byte)_iicMode & 0x0F) * 8;

            this.numUD_RegAddr.Maximum = (Decimal)Math.Pow(2, bitwidth_RegAddr) - 1;
            this.numUD_RegData.Maximum = (Decimal)Math.Pow(2,bitwidth_RegData) - 1;
        }

        private void btn_RegRead_Click(object sender, EventArgs e)
        {
            byte _chipAddr = (byte)(this.numUD_ChipAddr.Value * 2);
            IICMode _iicMode = IICModeDecode(this.cmb_IICMode.SelectedItem.ToString());
            int byteCnt_RegAddr = ((byte)_iicMode >> 4) & 0x0F;
            int byteCnt_RegData = ((byte)_iicMode & 0x0F);
            
            object regAddr = this.numUD_RegAddr.Value;

            object rdData = 0;
            bool ret = commDev.IICRead(_chipAddr, (object)regAddr, out rdData, _iicMode);
            if (ret)
            {
                this.numUD_RegData.Value = Convert.ToDecimal(rdData);
                PrintInfo(String.Format("IIC Read, Reg:0x{0} = 0x{1}\r\n", 
                    (Convert.ToUInt32(regAddr)).ToString(String.Format("X{0}", 2 * byteCnt_RegAddr)),
                    (Convert.ToUInt32(rdData)).ToString(String.Format("X{0}", 2 * byteCnt_RegData)) ));
            }
            else
                MessageBox.Show("IIC Read Failed!");
        }

        private void btn_RegWrite_Click(object sender, EventArgs e)
        {
            byte _chipAddr = (byte)(this.numUD_ChipAddr.Value *2);
            IICMode _iicMode = IICModeDecode(this.cmb_IICMode.SelectedItem.ToString());
            int byteCnt_RegAddr = ((byte)_iicMode >> 4) & 0x0F;
            int byteCnt_RegData = ((byte)_iicMode & 0x0F);

            object regAddr = this.numUD_RegAddr.Value;
            object regData = this.numUD_RegData.Value;

            bool ret = commDev.IICWrite(_chipAddr, regAddr, regData, _iicMode);
            if (ret)
            {
                PrintInfo(String.Format("IIC Read, Reg:0x{0} = 0x{1}\r\n",
                    (Convert.ToUInt32(regAddr)).ToString(String.Format("X{0}", 2 * byteCnt_RegAddr)),
                    (Convert.ToUInt32(regData)).ToString(String.Format("X{0}", 2 * byteCnt_RegData))));
            }
            else
                MessageBox.Show("IIC Write Failed!");
        }

        private void richtxt_ScriptView_KeyDown(object sender, KeyEventArgs e)
        {
            //Console.WriteLine("Down - > Control.ModifierKeys:{0}, Key.Control:{1}", Control.ModifierKeys, e.KeyCode);
            //Console.WriteLine("Down-> Rtb text length:{0}", richtxt_ScriptView.Text.Length);
            this.historyText = richtxt_ScriptView.Text;
            RichTextBox rtb = (RichTextBox)sender;
            #region Comment and Comment out
            //if (rtb.SelectionLength == 0)
            //    return;

            ///* Ctrl + / for comment out, Ctrl + Shift + / for uncomment *///
            string[] tempLines = rtb.Lines;
            int selStartBackup = rtb.SelectionStart;
            int startLine = rtb.GetLineFromCharIndex(rtb.SelectionStart);
            int startIx = rtb.GetFirstCharIndexFromLine(startLine);
            // Trim the "\n" of last line to avoid comment 1 line more 
            int selectLen = rtb.SelectedText.TrimEnd("\n".ToCharArray()).Length;    
            int endLine = rtb.GetLineFromCharIndex(rtb.SelectionStart + selectLen);
            //// select whole line text
            //rtb.Select(startIx, selStartBackup - startIx + rtb.SelectionLength);
            if ((Control.ModifierKeys & Keys.Control) == Keys.Control &&
               (Control.ModifierKeys & Keys.Shift) == Keys.Shift && e.KeyCode == Keys.Oem2)
            {
                // select whole line text
                if (selectLen == 0)
                    rtb.Select(startIx, rtb.Lines[startLine].TrimEnd("\n".ToCharArray()).Length);
                else
                    rtb.Select(startIx, selStartBackup - startIx + selectLen);
                //Uncomment                   
                string[] tempText = this.richtxt_ScriptView.SelectedText.Split('\n');
                for (int ix = 0; ix < tempText.Length; ix++)
                {
                    if (tempText[ix].StartsWith(@"//"))
                        tempText[ix] = tempText[ix].Remove(0, 2);
                }

                this.richtxt_ScriptView.SelectedText = string.Join("\n", tempText);

                for (int ix = startLine; ix <= endLine; ix++)
                {
                    SetFormat_Line(rtb, ix);
                }  
            }
            else if ((Control.ModifierKeys & Keys.Control) == Keys.Control && e.KeyCode == Keys.Oem2)
            {
                // select whole line text
                if (selectLen == 0)
                    rtb.Select(startIx, rtb.Lines[startLine].TrimEnd("\n".ToCharArray()).Length);
                else
                    rtb.Select(startIx, selStartBackup - startIx + selectLen);
                // comment out
                string[] tempText = this.richtxt_ScriptView.SelectedText.Split('\n');
                for (int ix = 0; ix < tempText.Length; ix++)
                {
                    tempText[ix] = @"//" + tempText[ix];
                }

                this.richtxt_ScriptView.SelectedText = string.Join("\n", tempText);

                for (int ix = startLine; ix <= endLine; ix++)
                {
                    SetFormat_Line(rtb, ix);
                }
            }
            //RefreshWholeTextFormat(rtb);
            rtb.SelectionStart = selStartBackup;
            #endregion
        }

        private void richtxt_ScriptView_KeyPress(object sender, KeyPressEventArgs e)
        {
            //Console.WriteLine("Press  - > Control.ModifierKeys:{0}, Key.Control:{1}", Control.ModifierKeys, Convert.ToInt32(e.KeyChar));
            //Console.WriteLine("Press -> Rtb text length:{0}", richtxt_ScriptView.Text.Length);

            RichTextBox rtb = (RichTextBox)sender;

            if ((Control.ModifierKeys & Keys.Control) == Keys.Control && (e.KeyChar == 0x16))   // Ctrl + v detected
            {
                try
                {
                    int endIx = rtb.SelectionStart;
                    //Console.WriteLine("selection start:{0}", endIx);

                    IDataObject dataObj = Clipboard.GetDataObject();
                    string clipboardText = string.Empty;
                    if (dataObj != null && dataObj.GetDataPresent(DataFormats.Text))
                    {
                        clipboardText = (string)dataObj.GetData(DataFormats.Text);
                        Console.WriteLine(clipboardText);
                    }

                    clipboardText = clipboardText.Replace("\r", "");
                    if (clipboardText.Length == 0)
                        return;

                    int startLine = rtb.GetLineFromCharIndex(endIx - clipboardText.Length);
                    int endLine = rtb.GetLineFromCharIndex(endIx);
                    for (int ix = startLine; ix <= endLine; ix++)
                    {
                        SetFormat_Line(rtb, ix);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
                finally { }

                //RefreshWholeTextFormat(sender as RichTextBox);
            }
        }

        private void richtxt_ScriptView_KeyUp(object sender, KeyEventArgs e)
        {
            //Console.WriteLine("UP - > Control.ModifierKeys:{0}, Key.Control:{1}", Control.ModifierKeys, e.KeyCode);
            //Console.WriteLine("UP -> Rtb text length:{0}", richtxt_ScriptView.Text.Length);
            RichTextBox rtb = (RichTextBox)sender;

            if (rtb.Text == historyText)
                return;

            if(IfValidKeyPress(e.KeyValue))
            {
                SetFormat_Line(rtb);
            }
        }





        #endregion Events

        private void FormScript_Load(object sender, EventArgs e)
        {
            //logWin.AppendLog(" ---- Log Windows ---- \r\n");
            //logWin.Focus();
            ////Ctrl + A 设置行间距1.5倍
            ////SendKeys.Send("^a");
            //SendKeys.SendWait("^a");
            ////SendKeys.Send("^5");SendKeys.Send("^a");
            //SendKeys.SendWait("^5");
        }

        private void chb_AutoRepeat_CheckedChanged(object sender, EventArgs e)
        {
            this.timer_autoRepeat.Enabled = chb_AutoRepeat.Checked;
            this.btn_Script_Excute.Enabled = !chb_AutoRepeat.Checked;
        }

        private void timer_autoRepeat_Tick(object sender, EventArgs e)
        {
            //this.timer_autoRepeat.Enabled = false;
            while ((excuteStatus != eExcuteStatus.Stopped) && this.chb_AutoRepeat.Checked)
                Thread.Sleep(5);
            
            this.btn_Script_Excute_Click(null, null);
            
        }

        private void numUD_AutoInterval_ValueChanged(object sender, EventArgs e)
        {
            this.timer_autoRepeat.Interval = (int)numUD_AutoInterval.Value;
        }
    }

    //public class ScriptCommand
    //{
    //    private string cmdDetail;
    //    public ScriptCommand(string cmdStr)
    //    {
    //        this.cmdDetail = cmdStr;


    //    }

    //    private bool ifValidCmd = false;
    //    public bool IfValidCmd
    //    { get { return this.ifValidCmd; } }


    //    private eCMDList sCmd;
    //    public eCMDList CMD
    //    { get { return sCmd; } }

    //    private string[] paramStr;
    //    public string[] Param
    //    { get { return paramStr; } }

    //    private void CheckAndDecode(string _cmd)
    //    {

    //    }

    //}

    public struct ScriptCMD
    {
        public eCMDList cmd;
        public int lineNo;
        public int paramCount;
        public List<string> paramStr;
        public List<UInt32> paramU32;
    }

    public enum eCMDList
    {
        SetIICMode,
        SetChipAddr,
        SetDelay,
        Pause,
        IICWrite,
        IICRead,
        IICBurstWrite,
        IICBurstRead,
        IICSetBit,
        IICSetBitField,
        IICReadBitField,
        IICClearBit,
        IICWaitUntil,
        IICWaitBitFieldUntil,
        TestBusWrite,
        TestBusRead,
        TestBusSetBitField,
        TestBusReadBitField,
        Unknown,
        None        
    }

    public enum eExcuteStatus
    {
        Stopped = 0,
        Running = 1,
        Paused = 2
    }
}
